package com.tspark.tspark1.zoo.util;

import com.tspark.tspark1.zoo.properties.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.Date;
import java.util.UUID;

/**
 * 工具类 用于解析或签发jwt令牌 这里不用静态方法是为了配置jwt属性到yml文件中
 *      签发时传入用户的id
 *      解析时：未报错即解析成功
 */
@Component
public class JwtUtil {
    //注入jwtProperties Bean注入发生在Bean实例化后 任何初始化方法前
    @Autowired
    private JwtProperties jwtProperties;

    //加密算法
    private final static SecureDigestAlgorithm<SecretKey, SecretKey> ALGORITHM = Jwts.SIG.HS256;


    /*
    这些是一组预定义的声明，它们 不是强制性的，而是推荐的 ，以 提供一组有用的、可互操作的声明 。
        iss: jwt签发者
        sub: jwt所面向的用户
        aud: 接收jwt的一方
        exp: jwt的过期时间，这个过期时间必须要大于签发时间
        nbf: 定义在什么时间之前，该jwt都是不可用的.
        iat: jwt的签发时间
        jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击
     */
    public String genAccessToken(Integer id,Integer isAdmin) {
        // 令牌id
        String uuid = UUID.randomUUID().toString();
        Date exprireDate = Date.from(Instant.now().plusSeconds(jwtProperties.getTtl()));

        return Jwts.builder()
                // 设置头部信息header
                .header()
                .add("typ", "JWT")
                .add("alg", "HS256")
                .and()
                // 设置自定义负载信息payload
                .claim("id", id)
                .claim("isAdmin", isAdmin)//是否为管理员 0否 1是
                // 令牌ID
                .id(uuid)
                // 过期日期
                .expiration(exprireDate)
                // 签发时间
                .issuedAt(new Date())
                // 主题
                .subject(jwtProperties.getSubject())
                // 签发者
                .issuer(jwtProperties.getIss())
                // 签名
                .signWith(Keys.hmacShaKeyFor(jwtProperties.getSecretKey().getBytes()), ALGORITHM)
                .compact();
    }
    /**
     * 解析token
     * @param token token
     * @return Jws<Claims>
     *
     *     关系解释： jwt有三部分 Header Payload 和 Signature
     *          Payload由Claim组成 这里的Jws<Claims> 意思就是 Jwt令牌 payload是Claims
     */
    //这里解析的是整个jwt 返回Jws
    public Jws<Claims> parseClaim(String token) {
        return Jwts.parser()
                .verifyWith(Keys.hmacShaKeyFor(jwtProperties.getSecretKey().getBytes()))
                .build()
                .parseSignedClaims(token);
    }

    public JwsHeader parseHeader(String token) {
        return parseClaim(token).getHeader();
    }

    public Claims parsePayload(String token) {
        return parseClaim(token).getPayload();
    }

    public int isAdmin(String token) {
        Claims claims = parsePayload(token);
        return (int)claims.get("isAdmin");
    }

    public int getUid(String token) {
        Claims claims = parsePayload(token);
        return (int) claims.get("id");
    }

}

